{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fe59d027-121a-4411-9dc6-0c1756f205e2",
   "metadata": {},
   "source": [
    "(alert_activations)=\n",
    "# Listing alert activations\n",
    "\n",
    "When an alert is activated by its configured trigger, MLRun saves the activation records that you can list, filter, etc. Alert activation records are stored in a partitioned table. The table is partitioned weekly and supports retention.\n",
    "The default retention period is 14 weeks. You can adjust it by setting `object_retentions.alert_activations` in the MLRun configuration. Specify the value in days.\n",
    "\n",
    "\n",
    "**In this section**\n",
    "- [List alert activations](#list-alert-activations)\n",
    "- [Filter by entity](#filter-by-entity)\n",
    "- [List alert activations for a given time range](#list-alert-activations-for-a-given-time-range)\n",
    "- [Group by attributes](#group-by-attributes)\n",
    "- [Aggregate by](#aggregate-by)\n",
    "\n",
    "## List alert activations\n",
    "\n",
    "You can list alert activations by:\n",
    "- MLRun's run db\n",
    "- A specific project\n",
    "- An alert config object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58d2b946-73f7-4f38-8236-4855e4ef4d4e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import mlrun\n",
    "\n",
    "run_db = mlrun.get_run_db()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "d49b918c-b0bf-4f17-862b-f8ae6ee9949e",
   "metadata": {},
   "outputs": [],
   "source": [
    "activations = run_db.list_alert_activations(\n",
    "    project=None,\n",
    "    name=None,\n",
    "    since=None,\n",
    "    until=None,\n",
    "    entity=None,\n",
    "    severity=None,\n",
    "    entity_kind=None,\n",
    "    event_kind=None,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c9ddafb-bb14-4ef4-aa95-3f57e2e0bb64",
   "metadata": {},
   "source": [
    "The method returns an instance of the {py:class}`~mlrun.common.schemas.alert.AlertActivations` class, which includes an activations attribute. This attribute is a list of {py:class}`~mlrun.common.schemas.alert.AlertActivation` objects, each containing the following fields:\n",
    "\n",
    "    id: int - activation id \n",
    "    name: str - alert config name\n",
    "    project: str - project name\n",
    "    severity: AlertSeverity - alert config severity\n",
    "    activation_time: datetime - time when alert was activated\n",
    "    entity_id: str - id of entity, for job as `{job-name}.{job_uid}`, for endpoint_id is `{model_endpoint_id}.{app_name}.result.{result_name}`\n",
    "    entity_kind: EventEntityKind - entity kind\n",
    "    criteria: AlertCriteria - alert config criteria\n",
    "    event_kind: EventKind - event kind\n",
    "    number_of_events: int - number of event of `event_kind` came from prev deactivation (or from beginning of time) to the current deactivation\n",
    "    notifications: list[notification_objects.NotificationState]\n",
    "    reset_time: Optional[datetime] - time when alert was reset (for auto reset policy is the same as activation time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "00d1ad4c-6c8e-432f-b97c-26bc264fe444",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AlertActivations(activations=[AlertActivation(id=4, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 5, 17, 674000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.db80cba0c4be4ee9b86a09cf12a89991', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 5, 17, 674000, tzinfo=datetime.timezone.utc)), AlertActivation(id=3, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 4, 47, 530000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.db80cba0c4be4ee9b86a09cf12a89991', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 4, 47, 530000, tzinfo=datetime.timezone.utc)), AlertActivation(id=2, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 4, 17, 349000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.58e25426ea154daab2afa4ebfe454c71', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 4, 17, 349000, tzinfo=datetime.timezone.utc)), AlertActivation(id=1, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 3, 47, 209000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.58e25426ea154daab2afa4ebfe454c71', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 3, 47, 209000, tzinfo=datetime.timezone.utc))], pagination=None)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "activations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee505c2f-e048-4b2d-824d-d9e6cd2f934f",
   "metadata": {},
   "source": [
    "This object is iterable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "40e2bac8-2dfb-4633-a888-c2a80f7c6278",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "job-failure-alert\n",
      "job-failure-alert\n",
      "job-failure-alert\n",
      "job-failure-alert\n"
     ]
    }
   ],
   "source": [
    "for activation in activations:\n",
    "    print(activation.name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2c8d2fa5-3d45-49c6-b96e-7666b4465ed4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "> 2024-12-11 11:52:10,062 [info] Project loaded successfully: {\"project_name\":\"default\"}\n"
     ]
    }
   ],
   "source": [
    "project = mlrun.get_or_create_project(\"default\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a012c3d0-11ce-41f1-bc9b-e8fb8d4967b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# list alert activations for a specific project\n",
    "activations = project.list_alert_activations(\n",
    "    name=None,\n",
    "    since=None,\n",
    "    until=None,\n",
    "    entity=None,\n",
    "    severity=None,\n",
    "    entity_kind=None,\n",
    "    event_kind=None,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5ae0441c-5105-47c3-aa43-78ce8215f8fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# list alert activations for a specific alert config\n",
    "alert_config = run_db.list_alerts_configs()[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "842fa453-a434-4794-a1a4-149b65d900d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "activations = alert_config.list_activations(\n",
    "    since=None,\n",
    "    until=None,\n",
    "    from_last_update=False,  # set to True to get activations only from the time when alert config was updated (takes precedence over \"since\" if both are passed)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0fd1abc-9f92-46eb-b787-19721b79c323",
   "metadata": {},
   "source": [
    "## Filter by entity\n",
    "List activations only for a specific entity, using its entity_id.\n",
    "\n",
    "The `entity_id` for the JOB `entity_kind` is formatted as `<job-name>.<job_uid>`. This is the only field in alert activation that supports wildcard search with asterix `*`. To enable a wildcard search, use `~` at the start of the entity parameter.\n",
    "For example, if you know the job name and want to find all activations related to it, pass the entity parameter as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "e2961fcd-ccf8-4f2e-a944-08baa86a0ad9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test-func-handler.db80cba0c4be4ee9b86a09cf12a89991\n",
      "test-func-handler.db80cba0c4be4ee9b86a09cf12a89991\n",
      "test-func-handler.58e25426ea154daab2afa4ebfe454c71\n",
      "test-func-handler.58e25426ea154daab2afa4ebfe454c71\n"
     ]
    }
   ],
   "source": [
    "activations = project.list_alert_activations(entity=\"~test-func-handler.*\")\n",
    "for activation in activations:\n",
    "    print(activation.entity_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "236497c2-e1eb-4f34-a8b5-a18c4f9969d7",
   "metadata": {},
   "source": [
    "If the `entity` parameter is passed as a string without a tilde (`~`), the search is performed for an exact match with the given string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "3821679c-050c-448d-9d28-d73b0396786b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "activations = project.list_alert_activations(\n",
    "    entity=\"test-func-handler.db80cba0c4be4ee9b86a09cf12a89991\"\n",
    ")\n",
    "len(activations)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15c4642b-2fac-4bbf-b69d-7769e087240b",
   "metadata": {},
   "source": [
    "## List alert activations for a given time range\n",
    "\n",
    "To filter, pass `since` and `until` as `datatime.datatime` objects:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "e2a5713e-67a5-4ea9-a113-fd9ec699a7ae",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import datetime\n",
    "\n",
    "activations = project.list_alert_activations(since=datetime.datetime.now())\n",
    "len(activations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "f1cf11f6-6521-456c-b38a-0eb44b00d8c7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "activations = project.list_alert_activations(\n",
    "    since=datetime.datetime(2024, 12, 11, 10, 5, 17, 674000),\n",
    "    until=datetime.datetime.now(),\n",
    ")\n",
    "len(activations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "be0c33ac-a2a8-40fc-bebe-e36818fc9df7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "alert_config = run_db.list_alerts_configs()[0]\n",
    "activations = alert_config.list_activations()\n",
    "len(activations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "827f02f7-e60a-4a29-82d6-c818dae1a3b8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# update alert config and get activations since last update\n",
    "alert_config = project.store_alert_config(alert_config)\n",
    "activations = alert_config.list_activations(from_last_update=True)\n",
    "len(activations)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32992696-e584-4b34-bcd7-320c613eebad",
   "metadata": {},
   "source": [
    "## Group by attributes\n",
    "The `group_by` method organizes alert activations into a dictionary based on specified attributes, making it easier to analyze or filter data.\n",
    "It groups activations by one or more attributes, such as project or severity, etc., with dictionary keys as tuples of the attribute values and values as lists of activations.\n",
    "This is especially useful for processing activations by categories, such as identifying alerts by their severity level or grouping them by projects, which can result in detailed insights."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "721b3dbd-c5c3-4ff4-bcd3-b90cf55a81c5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(run_db.list_alert_activations())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "081393b3-a32a-457c-b639-29ba58e38e34",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AlertActivation(id=5, name='job-failure-alert', project='default', severity=high, activation_time=datetime.datetime(2024, 12, 11, 13, 9, 57, 317000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.ed6094787c8c4817bd0c0a34c76fd004', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 13, 9, 57, 317000, tzinfo=datetime.timezone.utc))]"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# group by severity\n",
    "grouped = run_db.list_alert_activations().group_by(\"severity\")\n",
    "grouped[\"high\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "8c89ded9-9f40-4dc3-b98a-0db91ab29cac",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AlertActivation(id=6, name='job-failure-alert', project='default', severity=medium, activation_time=datetime.datetime(2024, 12, 11, 13, 10, 57, 379000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.c93108a238bf4e3196780e352de9561a', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 13, 10, 57, 379000, tzinfo=datetime.timezone.utc))]"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped[\"medium\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "cec26fb8-1f08-4413-9ab8-9e8f4041fc2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AlertActivation(id=4, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 5, 17, 674000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.db80cba0c4be4ee9b86a09cf12a89991', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 5, 17, 674000, tzinfo=datetime.timezone.utc)),\n",
       " AlertActivation(id=3, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 4, 47, 530000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.db80cba0c4be4ee9b86a09cf12a89991', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 4, 47, 530000, tzinfo=datetime.timezone.utc)),\n",
       " AlertActivation(id=2, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 4, 17, 349000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.58e25426ea154daab2afa4ebfe454c71', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 4, 17, 349000, tzinfo=datetime.timezone.utc)),\n",
       " AlertActivation(id=1, name='job-failure-alert', project='default', severity=low, activation_time=datetime.datetime(2024, 12, 11, 10, 3, 47, 209000, tzinfo=datetime.timezone.utc), entity_id='test-func-handler.58e25426ea154daab2afa4ebfe454c71', entity_kind=job, criteria=AlertCriteria(count=1, period=None), event_kind=failed, number_of_events=1, notifications=[NotificationState(kind='webhook', err='', summary=NotificationSummary(failed=0, succeeded=1))], reset_time=datetime.datetime(2024, 12, 11, 10, 3, 47, 209000, tzinfo=datetime.timezone.utc))]"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped[\"low\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "653538b8-2098-414a-888b-d7145b5cfc1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_keys([(medium, 'test-func-handler.c93108a238bf4e3196780e352de9561a'), (high, 'test-func-handler.ed6094787c8c4817bd0c0a34c76fd004'), (low, 'test-func-handler.db80cba0c4be4ee9b86a09cf12a89991'), (low, 'test-func-handler.58e25426ea154daab2afa4ebfe454c71')])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# group by severity and entity_id\n",
    "grouped = run_db.list_alert_activations().group_by(\"severity\", \"entity_id\")\n",
    "grouped.keys()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dcc53fbd-bf0d-463b-a504-0b58751ad0f9",
   "metadata": {},
   "source": [
    "## Aggregate by\n",
    "The `aggregate_by` method groups alert activations by specified attributes and applies a custom aggregation function to each group.\n",
    "It returns a dictionary where the keys are tuples of attribute values (e.g., (\"project1\", \"high\")), and the values are the result of the provided aggregation function, such as counts or summations of the grouped activations.\n",
    "This method is useful for summing up data, such as counting alerts per project or calculating statistics, enabling efficient analysis of alert activations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "709496d7-67a7-48ba-b12d-f7f5b0764777",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{medium: 1, high: 1, low: 4}"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# use aggregate_by to group alert activations by severity and compute the total number of events for each severity level:\n",
    "aggregated = run_db.list_alert_activations().aggregate_by(\n",
    "    [\"severity\"],\n",
    "    lambda activations: sum(activation.number_of_events for activation in activations),\n",
    ")\n",
    "aggregated"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mlrun-base",
   "language": "python",
   "name": "conda-env-mlrun-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
